<?php

  class String extends Base implements IString {

    private $string;

    public function __construct($string = String::EMPTY_STRING) {
      if (is_string($string)) {
        $this->string = $string;
      } else {
        throw new IllegalArgumentException("\$string parameter must be a string.");
      }
    }

    public function __invoke() {
      return $this->string;
    }

    public function __toString() {
      return $this->toString();
    }

    /** @todo implement Char ? */
    public function charAt(IInteger $index) {
      return new Char($this->string[$index->integerValue()]);
    }

    public function compareTo(IString $string) {
      return new Integer(strcmp($this->string, $string));
    }

    public function compareToIgnoreCase(IString $string) {
      return new Integer(strcasecmp($this->string, $string->toString()));
    }

    public function concat(IString $string) {
      return new String($this->string . $string->toString());
    }

    public function contains(IString $string) {
      return preg_match($string->toString(), $this->string) == 0 ? new Boolean(true) : new Boolean(false);
    }

    public function contentEquals(IString $string) {
      if (strlen($this->string) == $string->length()->integerValue()) {
        $testString = $string->toString();

        for ($i = 0; $i < $string->length()->integerValue(); ++$i) {
          if ($this->string[$i] != $testString[$i]) {
            return new Boolean(false);
          }
        }
        return new Boolean(true);
      } else {
        return new Boolean(false);
      }
    }

    public static function copyValueOf(array $array, IInteger $start = null, IInteger $length = null) {
      $tempString = "";
      $tempStart = $start == null ? 0 : $start->integerValue();
      $tempLength = $length == null ? count($array) - $start->integerValue() : $length->integerValue();

      for ($i = $tempStart; $i < $tempLength + 1; ++$i) {
        $tempString .= $array[$i];
      }

      return new String($tempString);
    }

    public function endsWith(IString $string) {
      if (substr($this->string, strlen($this->string) - $string->length()->integerValue()) == $string->toString()) {
        return new Boolean(true);
      } else {
        return new Boolean(false);
      }
    }

    public static function format(IString $string, $args) {
      return new String(sprintf($string->toString(), $args));
    }

    /** @todo implement Char ? */
    public function indexOf(IString $string) {
      $pos = strpos($this->string, $string->toString());

      return $pos === false ? new Integer(-1) : new Integer($pos);
    }

    public function isEmpty() {
      return new Boolean(empty($this->string));
    }

    public function length() {
      return new Integer(strlen($this->string));
    }

    public function lastIndexOf(IString $needle) {
      $pos = strrpos($this->string, $needle->toString());

      return $pos === false ? new Integer(-1) : new Integer($pos);
    }

    public function padLeft(IString $char, IInteger $length) {
      return new String(str_pad($this->string, $length->integerValue(), $char->toString(), STR_PAD_LEFT));
    }

    public function padRight(IString $char, IInteger $length) {
      return new String(str_pad($this->string, $length->integerValue(), $char, STR_PAD_RIGHT));
    }

    public function replace(IString $pattern, IString $replacement) {
      return new String(str_ireplace($pattern->toString(), $replacement->toString(), $this->string));
    }

    public function split(IString $pattern, IInteger $limit = null) {
      if (!is_null($limit)) {
        return explode($pattern->toString(), $this->string, $limit->integerValue());
      } else {
        return explode($pattern->toString(), $this->string);
      }
    }

    public function startsWith(IString $string) {
      if (substr($this->string, 0, $string->length()->integerValue()) == $string->toString()) {
        return new Boolean(true);
      } else {
        return new Boolean(false);
      }
    }

    public function subString(IInteger $start, IInteger $length = null) {
      if (!is_null($length)) {
        return new String(substr($this->string, $start->integerValue(), $length->integerValue()));
      } else {
        return new String(substr($this->string, $start->integerValue()));
      }
    }

    public function toCharArray() {
      $sequence = array();

      for ($i = 0; $i < strlen($this->string); ++$i) {
        array_push($sequence, $this->string[$i]);
      }

      return $sequence;
    }

    public function toLowerCase() {
      return new String(strtolower($this->string));
    }

    public function toString() {
      return $this->string;
    }

    public function toUpperCase() {
      return new String(strtoupper($this->string));
    }

    public function trim(IString $charlist = null) {
      if (!is_null($charlist)) {
        return new String(rtrim(ltrim($this->string, $charlist->toString()), $charlist->toString()));
      } else {
        return new String(ltrim(rtrim($this->string)));
      }
    }

    public function trimEnd(IString $charlist = null) {
      if (!is_null($charlist)) {
        return new String(rtrim($this->string, $charlist->toString()));
      } else {
        return new String(rtrim($this->string));
      }
    }

    public function trimStart(IString $charlist = null) {
      if (!is_null($charlist)) {
        return new String(ltrim($this->string, $charlist->toString()));
      } else {
        return new String(ltrim($this->string));
      }
    }

  }

?>
